/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
 *
 */

import { coreParameter, FileSet, MetricLogType, TaskDetails } from '@ohos/hvigor';
import { OHOS_ARK_COMPILE_SOURCE_MAP_DIR } from '@ohos/hvigor';
import * as fs from 'fs-extra';
import path from 'path';

import { BuildArtifactConst } from '../../const/build-directory-const.js';
import { LogCombineType } from '../../utils/log/log-combine-type.js';
import { execOhpmPack } from '../../utils/npm-utils.js';
import { ProcessUtils } from '../../utils/process-utils.js';
import { OhosHarTask } from '../task/ohos-har-task.js';
import { TargetTaskService } from '../service/target-task-service.js';
import { NpmCommandBuilder } from '../../builder/npm-command-builder.js';

/**
 * 打包Har包
 *
 * @since 2021/12/18
 */
export abstract class AbstractPackageHar extends OhosHarTask {
  protected abstract readonly taskTmpDir: string;
  protected readonly outputDir: string;
  protected readonly npmCommand: string[];
  protected readonly npmPath: string;

  declareOutputFiles(): FileSet {
    return new FileSet().addEntries([this.taskTmpDir, this.outputDir], { isDirectory: true });
  }

  protected constructor(taskService: TargetTaskService, taskDetails: TaskDetails) {
    super(taskService, taskDetails);

    this.outputDir = this.pathInfo.getModuleBuildOutputPath();

    this.npmPath = path.dirname(process.execPath);
    this.npmCommand = new NpmCommandBuilder(this.npmPath).addAllParams(['pack']);
  }

  declareExecutionCommand(): string {
    return `${this.npmCommand.toString()}`;
  }

  protected async doTaskAction(): Promise<void> {
    // 初始化模块的build目录
    fs.emptyDirSync(this.outputDir);
    this.isOhpmProject ? await this.executeOhpmPack() : await this.executeNpmPack();
    this.moveSourceMap();
  }

  private async executeOhpmPack(): Promise<void> {
    // ohpm pack .har
    const artifactName = this.targetData.getTargetOpt().output?.artifactName;
    const outputName = artifactName ? `${artifactName}` : `${this.moduleName}`;
    // 需要确保output文件夹存在
    fs.emptyDirSync(this.outputDir);
    await execOhpmPack(this.taskTmpDir, path.resolve(this.outputDir, `${outputName}.har`), this.durationEvent);
  }

  private async executeNpmPack() {
    // npm pack
    const inputData = {
      moduleName: this.moduleName,
      taskName: this.name,
      commandLine: this.npmCommand,
      commandOptions: { cwd: this.taskTmpDir },
    };

    const callback: Function = (packageName: string) => {
      fs.copySync(this.taskTmpDir, this.outputDir, {
        filter: (src) => {
          return (!fs.lstatSync(src).isDirectory() && src.endsWith(packageName)) || src === this.taskTmpDir;
        },
      });
    };

    const subToolTaskName = 'execute npm packaging command';
    const subToolDurationEvent = this.durationEvent.createSubEvent(subToolTaskName, '');
    subToolDurationEvent.start();

    if (!new ProcessUtils(this.moduleName, this.name).submitSyncExecutionWithReturn(this, this.getWorkerPool(), 'packageHar', inputData, callback)) {
      const packageName = await new ProcessUtils(this.moduleName, this.name).execute(inputData.commandLine, inputData.commandOptions, LogCombineType.DEBUG);
      callback(packageName.stdout.toString());
    }

    subToolDurationEvent.stop();
    subToolDurationEvent.setLog(subToolTaskName, MetricLogType.INFO);
  }

  private moveSourceMap() {
    // 用户没有指定路径，sourceMap默认将生成在cache下，在此阶段移动到output下
    if (!this.sdkInfo.hasRollUpPluginInEtsLoader) {
      return;
    }
    const defaultSourceMapPath = this.pathInfo.getSourceMapOriginPath(this.targetService);
    if (!fs.existsSync(defaultSourceMapPath)) {
      return;
    }
    if (coreParameter.properties[OHOS_ARK_COMPILE_SOURCE_MAP_DIR]) {
      // 若用户指定路径，sourceMap将生成在指定路径下
      const userConfigPath: string = coreParameter.properties[OHOS_ARK_COMPILE_SOURCE_MAP_DIR];
      const sourceMapPath: string = path.isAbsolute(userConfigPath)
        ? path.resolve(userConfigPath, this.moduleName)
        : path.resolve(this.projectModel.getProjectDir(), 'hvigor', userConfigPath, this.moduleName);
      fs.ensureDirSync(sourceMapPath);
      fs.copyFileSync(defaultSourceMapPath, path.resolve(sourceMapPath, BuildArtifactConst.SOURCEMAPS_MAP));
    } else {
      // 用户不指定，则通过default方法来读取路径
      fs.ensureDirSync(this.pathInfo.getDefaultSourceMapPath());
      fs.copyFileSync(defaultSourceMapPath, path.resolve(this.pathInfo.getDefaultSourceMapPath(), BuildArtifactConst.SOURCEMAPS_MAP));
    }
  }
}
